package com.gsi.webstore.platform.storefront.internal.order;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.intershop.beehive.core.capi.log.Logger;

import com.gsi.webstore.platform.storefront.capi.order.GSILineItemCtnrCalculationResultView;
import com.gsi.webstore.platform.storefront.capi.order.GSIOrderBO;
import com.gsi.webstore.platform.storefront.capi.order.GSIProductLineItemBO;
import com.gsi.webstore.platform.storefront.capi.shipping.GSIShippingBucketBO;
import com.gsi.webstore.platform.storefront.internal.shipping.GSIShippingBucketBOImpl;
import com.intershop.beehive.bts.capi.orderprocess.LineItemCtnr;
import com.intershop.beehive.core.capi.component.ComponentMgr;
import com.intershop.beehive.core.capi.domain.Domain;
import com.intershop.beehive.core.capi.domain.DomainMgr;
import com.intershop.beehive.core.capi.naming.NamingMgr;
import com.intershop.beehive.core.capi.preference.PreferenceMgr;
import com.intershop.beehive.core.capi.preference.PreferenceNotFoundException;
import com.intershop.beehive.core.capi.preference.ValueTypeViolationException;
import com.intershop.beehive.foundation.quantity.CurrencyException;
import com.intershop.beehive.foundation.quantity.Money;
import com.intershop.beehive.foundation.quantity.MoneyCalculator;
import com.intershop.component.shipping.capi.shippingbucket.ShippingBucket;
import com.intershop.component.shipping.capi.shippingbucketcomposer.ShippingBucketComposer;
import com.intershop.sellside.appbase.b2c.capi.calculation.LineItemCtnrCalculationResultView;
import com.intershop.sellside.appbase.b2c.capi.order.B2COrderBO;
import com.intershop.sellside.appbase.b2c.capi.order.B2COrderBOContext;
import com.intershop.sellside.appbase.b2c.capi.order.B2COrderBOProxy;
import com.intershop.sellside.appbase.b2c.capi.order.CostInformationBO;
import com.intershop.sellside.appbase.b2c.capi.order.ProductLineItemBO;
import com.intershop.sellside.appbase.b2c.capi.shipping.ShippingBucketBO;
import com.intershop.sellside.appbase.b2c.internal.order.LineItemCtnrBOImpl;
import com.intershop.sellside.appbase.b2c.internal.shipping.ShippingBucketBOImpl;

public class GSIOrderBOImpl extends B2COrderBOProxy implements GSIOrderBO
{
    private B2COrderBOContext context;
    private B2COrderBO delegate;
    private LineItemCtnrCalculationResultView calculationResultView;
    private List<GSIProductLineItemBO> productLineItems;
    private Boolean hiddenEdd = null;
    private Collection<CostInformationBO> salesTaxes;
    private Collection<CostInformationBO> dutiesAndFees;

    public GSIOrderBOImpl(final B2COrderBO delegate, final B2COrderBOContext context, final LineItemCtnrCalculationResultView calculationResultView)
    {
        super(delegate);
        this.delegate = delegate;
        this.context = context;
        this.calculationResultView = calculationResultView;
    }

    @Override
    public String getOrderID()
    {
        return delegate.getDocumentNo();
    }

    @Override
    public boolean isUnregisteredCheckout()
    {
        return delegate.getUser() == null || delegate.getUser().getProfile() == null;
    }

    public Collection<? extends GSIProductLineItemBO> getProductLineItems()
    {
        if (productLineItems != null)
        {
            return productLineItems;
        }

        productLineItems = new ArrayList<GSIProductLineItemBO>();
        for (ProductLineItemBO pliBO: delegate.getProductLineItems())
        {
            productLineItems.add(createProductLineItemBO(pliBO));
        }
        return productLineItems;
    }

    @Override
    public boolean isHiddenEDD()
    {
        if(hiddenEdd ==null)
        {
          Domain site=getSite();
          Domain preferenceDomain=null;
          String eddMode=EDD_MODE_ENABLED; //default
          if (null != site && null != site.getDomainName())
          {
              String siteName = site.getDomainName();
              if (siteName.endsWith("-Site"))
              {
                  DomainMgr domainMgr = (DomainMgr)NamingMgr.getManager(DomainMgr.class);
                  preferenceDomain = domainMgr.getDomainByName(siteName.substring(0, siteName.length()-5).concat("-Anonymous"));
              }
          }
          if (preferenceDomain!=null)
          {
              PreferenceMgr pmgr=(PreferenceMgr)NamingMgr.getInstance().lookupManager(PreferenceMgr.REGISTRY_NAME);
              try
              {
                  eddMode=pmgr.getStringPreference(EDD_MODE_CHANEL_PREFERENCE,preferenceDomain);
              }
              catch(PreferenceNotFoundException e)
              {
                  Logger.error(this, "preference " + EDD_MODE_CHANEL_PREFERENCE + " no found ", e);
              }
              catch(ValueTypeViolationException e)
              {
                  Logger.error(this, " value type violation ", e);
              }
          }
          hiddenEdd=Boolean.valueOf(!(EDD_MODE_ENABLED.equals(eddMode)));
        }
        return hiddenEdd.booleanValue();
    }

    private GSIProductLineItemBO createProductLineItemBO(ProductLineItemBO pliBO)
    {
        return new GSIProductLineItemBOImpl(pliBO, this, delegate.getCalculationResultView());
//        return (GSIProductLineItemBO) _context.getLineItemCtnrProxyFactory().createProductLineItemBO(this, pliBO, _context);
    }
    
    
    
    //
    // quick hack to fix V11EXT-2872
    // todo: needs rework
    //     
   
    @Override
    public Collection<? extends GSIShippingBucketBO> getShippingBuckets()
    {
        ShippingBucketComposer composer = NamingMgr.getManager(ComponentMgr.class).getComponent(
                "shippingBucketComposer");
        
        List<ShippingBucket> buckets = null;
        Field wrappedField;
        try
        {
            wrappedField = LineItemCtnrBOImpl.class.getDeclaredField("wrapped");
            wrappedField.setAccessible(true);
            
            buckets = composer.composeShippingBuckets((LineItemCtnr)wrappedField.get(delegate));
        }
        catch(NoSuchFieldException e)
        {
            Logger.error(this, " field not found ", e);
        }
        catch(SecurityException e)
        {
            Logger.error(this, " security fault ", e);
        }
        catch(IllegalArgumentException e)
        {
            Logger.error(this, " illegal argument ", e);
        }
        catch(IllegalAccessException e)
        {
            Logger.error(this, " illegal access ", e);
        }

        Set<GSIShippingBucketBO> bbos = new HashSet<GSIShippingBucketBO>(buckets.size());
        for(ShippingBucket shippingBucket : buckets)
        {
            ShippingBucketBO shippingBucketBO = new ShippingBucketBOImpl(shippingBucket, delegate, context, calculationResultView);
            bbos.add(new GSIShippingBucketBOImpl(shippingBucketBO, this, context, calculationResultView ));
        }
        return bbos;
    }    

    public Money getSalesTaxesAmount() throws CurrencyException
    {
        return calculationResultView.getTotalTax();
    }

    public Money getDutiesAndFeesAmount() throws CurrencyException
    {
        return ((GSILineItemCtnrCalculationResultView)calculationResultView).getTotalDutiesAndFees();
    }

    public Money getTaxesDutiesAndFeesAmount() throws CurrencyException
    {
        return MoneyCalculator.createLowPrecisionCalculator().add(getSalesTaxesAmount(), getDutiesAndFeesAmount());
    }

    public <T extends CostInformationBO> Collection<T> getSalesTaxes()
    {
        if (salesTaxes == null)
        {
            salesTaxes=((GSILineItemCtnrCalculationResultView)calculationResultView).getTaxGroups();
        }
        return (Collection<T>)salesTaxes;
    }

    public <T extends CostInformationBO> Collection<T> getDutiesAndFees()
    {
        if (dutiesAndFees == null)
        {
            dutiesAndFees=((GSILineItemCtnrCalculationResultView)calculationResultView).getDutiesAndFeesGroups();
        }
        return (Collection<T>)dutiesAndFees;
    }

    
    
}